﻿using Blm.PgsqlDriver.Helpers;
using Blm.RabbitMQ.MessageQueue;
using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Language.Resource;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using VisionCloud.Core.Model.Enums;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.DtoModel.RabbitMq;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Utility;

namespace VisionCloud.Service.Ms
{
    /// <summary>
    /// 报告服务类
    /// </summary>
    public class MsReportService
    {
        public ICSMSTaskRepository CSMSTaskRepository { get; set; }

        public IMsTaskPointsRepository MsTaskPointsRepository { get; set; }

        public IMsHouseMapPointRepository MsHouseMapPointRepository { get; set; }

        /// <summary>
        /// 多语言资源
        /// </summary>
        public IStringLocalizer<ServiceResource> Localizer { get; set; }

        public IRabbitMQProducer RabbitMQProducer { get; set; }

        public ILogger<MsReportService> logger { get; set; }

        /// <summary>
        /// 本地文件访问服务URL
        /// </summary>
        private static readonly string fileServer = ConfigHelper.GetValue<string>("FileServer");

        /// <summary>
        /// MinIO文件存储地址
        /// </summary>
        private static readonly string taskReportData = ConfigHelper.GetValue<string>("TaskReportData");

        /// <summary>
        /// 服务器域名
        /// </summary>
        private static readonly string webUrl = ConfigHelper.GetValue<string>("WebUrl");

        /// <summary>
        /// 获取报告列表(旧版)
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<PagerDto> GetReportList(ReportSearchDto condition)
        {
            if (string.IsNullOrWhiteSpace(condition.ProjectId))
            {
                throw new OperationException(Localizer["YB0008"].Value);
            }
            List<ReportDto> reportDtos = new List<ReportDto>();
            PagerDto pagerDto = new PagerDto();
            pagerDto.PageIndex = condition.PageIndex;  // 前端初始分页页码为1
            pagerDto.PageSize = condition.PageSize;
            pagerDto.Result = reportDtos;

            StringBuilder sbCount = new StringBuilder();
            sbCount.AppendLine(VisionCloudGlobalContext.GetSection("sqls:sql:query_report_list"));

            StringBuilder sb = new StringBuilder();
            sb.Append(VisionCloudGlobalContext.GetSection("sqls:sql:query_report_list02"));

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>();
            if (condition.UserId != Guid.Empty)
            {
                parameters.Add(new NpgsqlParameter("@UserId", condition.UserId));
            }

            parameters.Add(new NpgsqlParameter("@CompanyGuid", OperatorProvider.Get().CompanyGuid));
            parameters.Add(new NpgsqlParameter("@PageSize", condition.PageSize));
            parameters.Add(new NpgsqlParameter("@OFFSET", pagerDto.PageDataBeginIndex));

            if (!string.IsNullOrEmpty(condition.TaskName))
            {
                condition.TaskName = condition.TaskName.Replace("%", "\\%").Replace("_", "\\_");
                int? taskType = null;
                if (condition.TaskName.Equals("自") || condition.TaskName.Equals("自检"))
                {
                    taskType = 1;
                }
                else if (condition.TaskName.Equals("巡") || condition.TaskName.Equals("巡检"))
                {
                    taskType = 2;
                }
                string conditionStr = taskType.HasValue ? $@" or mt.""TaskType""={taskType.Value}" : string.Empty;
                string temp = $" and (task.\"TaskName\" like @TaskName or task.\"ProjectStage\" like @TaskName {conditionStr})";
                sb.AppendLine(temp);
                sbCount.AppendLine(temp);

                parameters.Add(new NpgsqlParameter("@TaskName", "%" + condition.TaskName + "%"));
            }

            if (!string.IsNullOrEmpty(condition.ProjectId))
            {
                string temp = " and task.\"ProjectId\" =@ProjectId";
                sb.AppendLine(temp);
                sbCount.AppendLine(temp);

                parameters.Add(new NpgsqlParameter("@ProjectId", condition.ProjectId.ToGuid()));
            }

            int count = PgSqlHelper.QueryScalar<int>(sbCount.ToString(), parameters.ToArray());
            pagerDto.Total = count;

            if (!string.IsNullOrEmpty(condition.OrderBy))
            {
                var orderField = condition.OrderBy == "TaskType" ? "mt.\"TaskType\"" : $"task.\"{condition.OrderBy}\"";

                if (string.IsNullOrEmpty(condition.AscDesc) || condition.AscDesc.ToLower() == "desc")
                {
                    sb.AppendLine($" order by {orderField} desc");
                    pagerDto.AscDesc = "desc";
                }
                else
                {
                    sb.AppendLine($" order by {orderField} asc");
                    pagerDto.AscDesc = "asc";
                }
            }
            else
            {
                if (string.IsNullOrEmpty(condition.OrderBy))
                {
                    sb.AppendLine($" order by ( CASE WHEN cs.\"IsRead\" = TRUE OR cs.\"IsRead\" IS NULL THEN FALSE ELSE TRUE END ) desc,task.\"ReportUploadDateTime\" desc ");
                }

                sb.AppendLine(" limit @PageSize OFFSET @OFFSET");
            }

            var reportList = await PgSqlHelper.QueryListAsync<ReportDto>(sb.ToString(), parameters.ToArray());
            foreach (var reportDto in reportList)
            {
                /*
                 * 1.以下数据要转换成URL:\要换成/兼容操作系统
                 *   原位标注图路径数组：HouseMapPreviewImage[];
                 *   汇总报告路径：SummaryReportPath；
                 *   报告打包文件下载路径：CompressedAllFilePath；
                 *   点云打包下载路径：CloudPointCompressedFilePath
                 *   ResultDataFilePath：
                 *   Z:\\dotcloud\\minio\\data\\task-report-data\\5304919\\72d50bd6-418c-47b2-b19a-354f9957b06e
                 */

                reportDto.TaskType = reportDto.TaskType == "1" ? "自检" : "巡检";
                reportDto.ResultDataFilePath = reportDto.ResultDataFilePath.Replace(@"\", @"/");
                int pIndex = reportDto.ResultDataFilePath.IndexOf("task-report-data");
                if (pIndex == -1)
                {
                    throw new OperationException(Localizer["YB0188"].Value);
                }

                #region 原位标注图

                reportDto.HouseMapPreviewImage = new List<string>();
                string previewImageDri = Path.Combine(reportDto.ResultDataFilePath, reportDto.TaskName, "原位标注图").Replace(@"\", @"/");
                if (Directory.Exists(previewImageDri))
                {
                    var files = Directory.GetFiles(previewImageDri)?.OrderBy(f => new FileInfo(f).Name).ToList();
                    if (files != null && files.Count > 0)
                    {
                        foreach (var file in files)
                        {
                            string temp = file.Replace(@"\", @"/");
                            temp = temp.Substring(pIndex);
                            temp = StatisService.ToTaskReportUrl(temp);
                            reportDto.HouseMapPreviewImage.Add(temp);
                        }
                    }
                }

                #endregion 原位标注图

                #region 汇总报告

                string summaryReportPdfUrl = Path.Combine(reportDto.ResultDataFilePath, reportDto.TaskName, "测量报告", "测量报告.pdf").Replace(@"\", @"/");
                // 文件不存在按照新命名规范找
                if (!File.Exists(summaryReportPdfUrl))
                {
                    string path = Path.Combine(reportDto.ResultDataFilePath, reportDto.TaskName, "测量报告");
                    if (Directory.Exists(path))
                    {
                        var files = Directory.GetFiles(path, "*_汇总报告.pdf");
                        if (files != null && files.Length > 0)
                        {
                            summaryReportPdfUrl = files[0];
                        }
                    }
                    else
                    {
                        Logger.Error($"GetReportList：汇总报告不存在{path}");
                    }
                }
                if (pIndex >= 0)
                {
                    reportDto.SummaryReportPath = StatisService.ToTaskReportUrl(summaryReportPdfUrl.Substring(pIndex));
                }

                #endregion 汇总报告

                // 压缩数据
                string deviceNoTaskId = reportDto.ResultDataFilePath.Substring(pIndex + "task-report-data/".Length);
                pIndex = deviceNoTaskId.IndexOf("/");
                string deviceNo = deviceNoTaskId.Substring(0, pIndex);
                string taskId = deviceNoTaskId.Substring(pIndex + 1, 36);
                string uploadGuid = deviceNoTaskId.Substring(pIndex + 1 + 36 + 1, 36);
                string tempUrl = Path.Combine("task-data-backup", deviceNo, taskId, uploadGuid + ".zip").Replace(@"\", @"/");
                reportDto.CompressedAllFilePath = StatisService.ToTaskReportUrl(tempUrl, true);
                // 点云目录

                tempUrl = Path.Combine("task-dotcloud-data", deviceNo, taskId).Replace(@"\", @"/");
                reportDto.CloudPointCompressedFilePath = StatisService.ToDotCloudUrl(tempUrl);
                reportDto.ResultDataFilePath = "*";
                reportDtos.Add(reportDto);
            }

            if (reportDtos.Count > 0)
            {
                var ids = reportDtos.Select(p => p.TaskId).ToList();
                var indexList = await GetTaskPointIndexList(ids);
                foreach (var item in reportDtos)
                {
                    item.FinishIndexList = indexList.Where(p => p.id == item.TaskId).Select(p => p.index).OrderBy(p => p).ToList();
                }
            }

            return pagerDto;
        }

        /// <summary>
        /// 获取报告列表(新版)
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<PagerDto> GetReportList(ReportListSearchDto condition)
        {
            PagerDto pagerDto = new PagerDto
            {
                PageIndex = condition.PageIndex,
                PageSize = condition.PageSize
            };

            List<ReportDto> reportList = await GetPaperDto(condition, pagerDto);
            switch (condition.MeasureType)
            {
                case MeasureTypeEnum.实测实量任务:
                    await GetMeasureFinishIndexList(reportList);
                    break;

                case MeasureTypeEnum.建模任务:
                case MeasureTypeEnum.外立面任务:
                    GetFinishIndexList(reportList);
                    break;

                default:
                    throw new OperationException("该任务类型暂不支持查询报告列表");
            }

            pagerDto.Result = reportList;
            return pagerDto;
        }

        /// <summary>
        /// 获取报告列表
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="pagerDto"></param>
        /// <returns></returns>
        private async Task<List<ReportDto>> GetPaperDto(ReportListSearchDto condition, PagerDto pagerDto)
        {
            List<ReportDto> reportDtoList = new List<ReportDto>();

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>
            {
                new NpgsqlParameter("@UserId",condition.UserId),
                new NpgsqlParameter("@CompanyGuid",OperatorProvider.Get().CompanyGuid),
                new NpgsqlParameter("@ProjectId",condition.ProjectId),
                new NpgsqlParameter("@MeasureType",condition.MeasureType.ToInt32().ToString())
            };

            StringBuilder sbCount = new StringBuilder();
            sbCount.AppendLine(VisionCloudGlobalContext.GetSection("sqls:sql:query_paper_dto01"));

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(VisionCloudGlobalContext.GetSection("sqls:sql:query_paper_dto02"));

            if (!string.IsNullOrEmpty(condition.TaskName))
            {
                condition.TaskName = condition.TaskName.Replace("%", "\\%").Replace("_", "\\_");
                parameters.Add(new NpgsqlParameter("@TaskName", $"%{condition.TaskName}%"));
                string likeSql;
                if (condition.MeasureType == MeasureTypeEnum.实测实量任务)
                {
                    int? taskType = null;
                    if (condition.TaskName.Equals("自") || condition.TaskName.Equals("自检"))
                    {
                        taskType = 1;
                    }
                    else if (condition.TaskName.Equals("巡") || condition.TaskName.Equals("巡检"))
                    {
                        taskType = 2;
                    }
                    string conditionStr = taskType.HasValue ? $@" or mt.""TaskType""={taskType.Value}" : string.Empty;
                    likeSql = $@" and (task.""TaskName"" like @TaskName or task.""ProjectStage"" like @TaskName {conditionStr})";
                }
                else
                {
                    likeSql = @" and (task.""TaskName"" like @TaskName)";
                }
                sb.AppendLine(likeSql);
                sbCount.AppendLine(likeSql);
            }

            int count = PgSqlHelper.QueryScalar<int>(sbCount.ToString(), parameters.ToArray());
            pagerDto.Total = count;

            if (!string.IsNullOrEmpty(condition.OrderBy))
            {
                var orderField = condition.OrderBy == "TaskType" ? @"mt.""TaskType""" : $@"task.""{condition.OrderBy}""";

                pagerDto.AscDesc = string.IsNullOrEmpty(condition.AscDesc) ? "desc" : condition.AscDesc;
                sb.AppendLine($" order by {orderField} {pagerDto.AscDesc}");
            }
            else
            {
                sb.AppendLine($@" order by ( CASE WHEN cs.""IsRead"" = TRUE OR cs.""IsRead"" IS NULL THEN FALSE ELSE TRUE END ) desc,task.""ReportUploadDateTime"" desc ");
            }

            sb.AppendLine(" limit @PageSize OFFSET @OFFSET ");
            parameters.Add(new NpgsqlParameter("@PageSize", condition.PageSize));
            parameters.Add(new NpgsqlParameter("@OFFSET", pagerDto.PageDataBeginIndex));

            var list = await PgSqlHelper.QueryListAsync<ReportDto>(sb.ToString(), parameters.ToArray());
            foreach (var item in list)
            {
                item.TaskType = item.TaskType == "1" ? "自检" : "巡检";
                item.HouseTypes = await MsHouseMapPointRepository.GetHouseTypes(item.TaskId);
            }
            reportDtoList.AddRange(list);

            return reportDtoList;
        }

        /// <summary>
        /// 获取实测任务已完成子站点
        /// </summary>
        /// <param name="reportDtos"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private async Task GetMeasureFinishIndexList(List<ReportDto> reportDtos)
        {
            if (reportDtos.IsEmpty())
                return;

            foreach (var reportDto in reportDtos)
            {
                #region 报告路径处理

                /*
                 * 1.以下数据要转换成URL:\要换成/兼容操作系统
                 *   原位标注图路径数组：HouseMapPreviewImage[];
                 *   汇总报告路径：SummaryReportPath；
                 *   报告打包文件下载路径：CompressedAllFilePath；
                 *   点云打包下载路径：CloudPointCompressedFilePath
                 *   ResultDataFilePath：
                 *   Z:\\dotcloud\\minio\\data\\task-report-data\\5304919\\72d50bd6-418c-47b2-b19a-354f9957b06e
                 */

                var resultDataFilePath = reportDto.ResultDataFilePath.Replace(@"\", @"/");
                int pIndex = resultDataFilePath.IndexOf("task-report-data");
                if (pIndex == -1)
                {
                    throw new OperationException(Localizer["YB0188"].Value);
                }

                if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")?.ToLower() == "local")
                {
                    resultDataFilePath = resultDataFilePath.Replace("/shareFiles/", "d:/");
                }

                #region 原位标注图

                reportDto.HouseMapPreviewImage = new List<string>();
                string previewImageDri = Path.Combine(resultDataFilePath, reportDto.TaskName, "原位标注图").Replace(@"\", @"/");
                if (Directory.Exists(previewImageDri))
                {
                    var files = Directory.GetFiles(previewImageDri)?.OrderBy(f => new FileInfo(f).Name).ToList();
                    if (files != null && files.Count > 0)
                    {
                        foreach (var file in files)
                        {
                            string temp = file.Replace(@"\", @"/");
                            temp = temp.Substring(pIndex);
                            temp = StatisService.ToTaskReportUrl(temp);
                            reportDto.HouseMapPreviewImage.Add(temp);
                        }
                    }
                }

                #endregion 原位标注图

                #region 汇总报告

                string summaryReportPdfUrl = Path.Combine(resultDataFilePath, reportDto.TaskName, "测量报告", "测量报告.pdf").Replace(@"\", @"/");
                // 文件不存在按照新命名规范找
                if (!File.Exists(summaryReportPdfUrl))
                {
                    string path = Path.Combine(resultDataFilePath, reportDto.TaskName, "测量报告");
                    // 文件不存在
                    summaryReportPdfUrl = string.Empty;
                    if (Directory.Exists(path))
                    {
                        var files = Directory.GetFiles(path, "*_汇总报告.pdf");
                        if (files != null && files.Length > 0)
                        {
                            summaryReportPdfUrl = files[0];
                        }
                    }
                    else
                    {
                        Logger.Info($"GetReportList：汇总报告不存在{path}");
                    }
                }
                if (pIndex >= 0 && !string.IsNullOrWhiteSpace(summaryReportPdfUrl))
                {
                    reportDto.SummaryReportPath = StatisService.ToTaskReportUrl(summaryReportPdfUrl.Substring(pIndex));
                }

                #endregion 汇总报告

                #endregion 报告路径处理
            }

            var ids = reportDtos.Select(p => p.TaskId).ToList();
            var indexList = await GetTaskPointIndexList(ids);
            foreach (var reportDto in reportDtos)
            {
                reportDto.FinishIndexList = indexList.Where(p => p.id == reportDto.TaskId).Select(p => p.index).OrderBy(p => p).ToList();
            }

            //检测上传的文件是否存在热力图基础数据目录
            //4.3之前的版本上传的文件不存在热力图基础数据目录
            foreach (var reportDto in reportDtos)
            {
                if (reportDto.FinishIndexList == null || reportDto.FinishIndexList.Count == 0)
                {
                    reportDto.HasHotMap = false;
                }
                else
                {
                    //站点目录
                    var pointDic = $"{reportDto.TaskId}_{reportDto.FinishIndexList.FirstOrDefault()}";
                    //baseHotMap目录
                    var basePath = Path.Combine(reportDto.ResultDataFilePath, reportDto.TaskName, MsTaskService.DefaultHotMapDir, pointDic);
                    var hotMapPath = Path.Combine(basePath, "baseHotMap");
                    //3D目录
                    var threePath = Path.Combine(reportDto.ResultDataFilePath, reportDto.TaskName, "3D", pointDic);
                    // 3DSetting.ini文件
                    var settingFile = Path.Combine(reportDto.ResultDataFilePath, reportDto.TaskName, "3D", "3DSetting.ini");
                    // 3D目录、baseHotMap目录和3DSetting.ini都存在时才激活3D按钮
                    reportDto.HasHotMap = Directory.Exists(basePath) && Directory.Exists(hotMapPath) && Directory.Exists(threePath) && File.Exists(settingFile);
                }

                #region 隐藏物理盘路径

                reportDto.ResultDataFilePath = "*";

                #endregion 隐藏物理盘路径
            }
        }

        /// <summary>
        /// 获取已完成任务站点
        /// </summary>
        /// <param name="reportDtos"></param>
        /// <returns></returns>
        private void GetFinishIndexList(List<ReportDto> reportDtos)
        {
            if (reportDtos.IsEmpty())
                return;

            var ids = reportDtos.Select(p => p.TaskId).ToList();
            var indexList = MsTaskPointsRepository.GetFinishPoints(ids);
            foreach (var reportDto in reportDtos)
            {
                reportDto.FinishIndexList = indexList.Where(p => p.Id == reportDto.TaskId).Select(p => (long)p.Index).OrderBy(p => p).ToList();
                reportDto.HasHotMap = reportDto.FinishIndexList.IsNotEmpty();
            }

            reportDtos.ForEach(p => { p.ResultDataFilePath = "*"; });
        }

        /// <summary>
        /// 获取已完成测量报告的站点
        /// </summary>
        /// <param name="ids">任务Id列表</param>
        /// <returns></returns>
        private async ValueTask<List<(Guid id, long index)>> GetTaskPointIndexList(List<Guid> ids)
        {
            List<(Guid, long)> indexList = new List<(Guid, long)>();
            if (ids == null || ids.Count == 0)
                return indexList;

            var idString = string.Join(",", ids.Select(p => $"'{p}'"));
            string sql = $"select uuid,index from taskpointtable  where tackpointjson is not null and uuid in ({idString})";

            indexList = await PgSqlHelper.QueryListAsync<(Guid, long)>(sql);
            return indexList;
        }

        /// <summary>
        /// 批量删除报告
        /// </summary>
        /// <param name="listTaskId">任务id列表</param>
        /// <returns></returns>
        public async Task<bool> BatchDeleteReport(List<Guid> listTaskId)
        {
            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>();
            StringBuilder sbInWhereP = new StringBuilder();

            for (int i = 0; i < listTaskId.Count; i++)
            {
                string pName = "Task" + i.ToString();
                sbInWhereP.Append("@" + pName + ",");
                parameters.Add(new NpgsqlParameter(pName, listTaskId[i]));
            }

            // 删除报告同时删除进度、质量和工效数据
            string where = "(" + sbInWhereP.ToString().Trim(',') + ")";
            string sql = string.Format(@"UPDATE ""CSMSTask"" SET ""IsDeleteReport"" = TRUE,""IsApproved"" = FALSE WHERE ""TaskId"" IN {0};
                                        UPDATE ""MsTask"" SET ""IsDeleted"" = TRUE WHERE ""TaskId"" IN {0};
                                        DELETE FROM ""MsSProgressAnalysis"" WHERE ""TaskId"" IN {0};
                                        DELETE FROM ""MsSQualityAnalysis"" WHERE ""TaskId"" IN {0};
                                        DELETE FROM ""MsSPersonnelEfficiency"" WHERE ""TaskId"" IN {0};", where);

            int affrows = 0;
            PgSqlHelper.Transaction(() =>
            {
                affrows = PgSqlHelper.ExecuteNonQuery(CommandType.Text, sql, parameters.ToArray());
            });
            if (affrows > 0)
            {
                await PushDeviceStatistics(listTaskId);
            }
            return affrows > 0;
        }

        /// <summary>
        /// 推送设备统计数据到FMS系统
        /// </summary>
        /// <param name="listTaskId"></param>
        /// <returns></returns>
        private async Task PushDeviceStatistics(List<Guid> listTaskId)
        {
            var ids = (await CSMSTaskRepository.WhereAsync(p => listTaskId.Contains(p.TaskId))).Select(p => p.DeviceGuid);
            foreach (var item in ids)
            {
                //发送队列消息，重新统计该设备的数据并发送到FMS系统
                await RabbitMQProducer.SendAsync(new MsDevicePushDto
                {
                    Type = 1,
                    DeviceId = item
                });
            }
        }

        /// <summary>
        /// 下载单个报告文件
        /// </summary>
        /// <param name="listTaskId">任务Id列表</param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        public async Task<List<string>> DownloadReport(List<Guid> listTaskId, string folderName = "download")
        {
            if (listTaskId == null || listTaskId.Count == 0)
            {
                throw new OperationException(Localizer["YB0189"].Value);
            }
            else if (listTaskId.Count > 30)
            {
                //每次最多只能下载{0}个报告
                throw new OperationException(string.Format(Localizer["LimitDownloadReport"].Value, 30));
            }

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>();
            string condition = string.Empty;
            for (int i = 0; i < listTaskId.Count; i++)
            {
                parameters.Add(new NpgsqlParameter()
                {
                    ParameterName = $"TaskId{i}",
                    Value = listTaskId[i],
                });
                condition += $"@TaskId{i},";
            }
            condition = condition.Substring(0, condition.Length - 1);

            // 查询要下载报告数据
            string sql = string.Format(
                VisionCloudGlobalContext.GetSection("sqls:sql:query_download_report_data"), condition);
            string dirPath = $"{taskReportData}/{folderName}/";
            var urls = new List<string>();

            List<FileDownloadDto> reportList = new List<FileDownloadDto>();

            var list = await PgSqlHelper.QueryListAsync<ReportDownloadDto>(sql, parameters.ToArray());
            if (list.Count == 0)
                throw new OperationException(Localizer["YB0192"].Value);

            string reportOldDir = null;
            string fileName = null;
            foreach (var item in list)
            {
                var taskNameArray = item.TaskName.ToString().Split("-");
                if (taskNameArray == null || taskNameArray.Length != 4)
                {
                    throw new OperationException(Localizer["StatisServiceTaskNameError"].Value);
                }
                //任务分类，0：实测实量任务，1:机器人任务；2:建模；3:排版
                var measureType = item.MeasureType.ToInt32();
                if (measureType == 0)
                {
                    //报告存储目录
                    reportOldDir = Path.Combine(item.ResultDataFilePath, item.TaskName);
                    if (!Directory.Exists(reportOldDir))
                        throw new OperationException(Localizer["StatisServiceReportNotExists"].Value);

                    //新的文件名
                    fileName = $"{taskNameArray[0]}-{taskNameArray[1]}-{taskNameArray[2]}-{item.ProjectStage}-{item.TaskProperty}-{item.TaskType}_{item.TaskId}";
                }
                else if (measureType == 2)
                {
                    //报告存储目录
                    reportOldDir = item.ResultDataFilePath;
                    if (!Directory.Exists(reportOldDir))
                        throw new OperationException(Localizer["StatisServiceReportNotExists"].Value);

                    //新的文件名
                    fileName = $"{taskNameArray[0]}-{taskNameArray[1]}-{taskNameArray[2]}-{item.ProjectStage}_{item.TaskId}";
                }

                if (!string.IsNullOrEmpty(fileName))
                {
                    reportList.Add(new FileDownloadDto
                    {
                        ZipFilePath = $"{dirPath}{fileName}.zip",
                        ReportOldDir = reportOldDir,
                        ReportDownloadDir = $"{dirPath}{fileName}",
                        TaskId = item.TaskId,
                        MeasureType = measureType
                    });
                }
            }

            //多线程下载
            List<Task> taskList = new List<Task>();
            foreach (var report in reportList)
            {
                Task task = new Task(() =>
                {
                    // 如压缩文件已存在直接返回
                    if (File.Exists(report.ZipFilePath))
                    {
                        urls.Add(StatisService.ToTaskReportUrl(report.ZipFilePath));
                    }
                    else
                    {
                        // 确保打包文件目录已删除，再打包
                        if (Directory.Exists(report.ReportDownloadDir))
                            Directory.Delete(report.ReportDownloadDir, true);

                        if (report.MeasureType == 0)
                        {
                            var deleteDirList = new List<string>
                            {
                                "3D",
                                "基础数据",
                                "热力图分享数据",
                                "热力图基础数据",
                                "分户报告",
                                "IFC文件",//实测实量需要过滤IFC数据
                            };
                            MoveFileAndCompressDir(report.ZipFilePath, report.ReportOldDir, deleteDirList);
                        }
                        else if (report.MeasureType == 2)
                        {
                            CompressModelingResultDir(report);
                        }

                        //删除已经不需要的文件夹
                        if (Directory.Exists(report.ReportDownloadDir))
                            Directory.Delete(report.ReportDownloadDir, true);

                        if (File.Exists(report.ZipFilePath))
                            urls.Add(StatisService.ToTaskReportUrl(report.ZipFilePath));
                    }
                });
                task.Start();
                taskList.Add(task);
            }
            await Task.WhenAll(taskList);

            return urls;
        }

        /// <summary>
        /// 压缩建模任务的报告目录
        /// </summary>
        /// <param name="report"></param>
        /// <returns></returns>
        private void CompressModelingResultDir(FileDownloadDto report)
        {
            try
            {
                var indexList = MsTaskPointsRepository.GetFinishPoints(new List<Guid> { report.TaskId });
                foreach (var item in indexList)
                {
                    var oldDir = Path.Combine(report.ReportOldDir, item.Index.ToString(), "ifc_output");
                    if (!Directory.Exists(oldDir))
                        continue;

                    var ifcFile = Directory.GetFiles(oldDir, "*.ifc").FirstOrDefault();
                    if (File.Exists(ifcFile))
                    {
                        var newDir = Path.Combine(report.ReportDownloadDir, item.Index.ToString(), "ifc_output");
                        if (!Directory.Exists(newDir))
                            Directory.CreateDirectory(newDir);
                        var ifcFileName = Path.GetFileName(ifcFile);
                        var newFile = Path.Combine(newDir, ifcFileName);
                        File.Copy(ifcFile, newFile, true);
                    }
                }
                FileInfoUtil.CreateFromDirectory(report.ReportDownloadDir, report.ZipFilePath);
            }
            catch (Exception ex)
            {
                logger.LogError($"建模任务下载报错：{ex.Message}，{ex.StackTrace}", ex);
            }
        }

        /// <summary>
        /// 移动文件夹并打包压缩文件夹
        /// </summary>
        /// <param name="zipFile">新的压缩文件</param>
        /// <param name="reportDir">报告资源文件所在目录</param>
        /// <param name="deleteDirList">要删除的目录</param>
        private void MoveFileAndCompressDir(string zipFile, string reportDir, List<string> deleteDirList)
        {
            var tempDir = Path.Combine(taskReportData, "downloadtemp");
            if (!Directory.Exists(tempDir))
            {
                Directory.CreateDirectory(tempDir);
            }
            List<ReportMoveDto> moveList = new List<ReportMoveDto>();

            try
            {
                var stime = DateTime.Now;

                foreach (var item in deleteDirList)
                {
                    var searchDirList = Directory.GetDirectories(reportDir, item, SearchOption.AllDirectories);
                    if (searchDirList.IsEmpty())
                        continue;

                    foreach (var dir in searchDirList)
                    {
                        var arr = dir.Split("task-report-data");
                        var childDir = arr[1];
                        if (childDir.StartsWith("\\") || childDir.StartsWith("/"))
                            childDir = childDir.Substring(1);

                        var newDir = Path.Combine(tempDir, childDir);
                        if (!Directory.Exists(newDir))
                        {
                            //创建完整的目录
                            Directory.CreateDirectory(newDir);
                            //仅仅删除最后一级的目录，此代码不能删掉
                            Directory.Delete(newDir, true);
                        }
                        moveList.Add(new ReportMoveDto { OldDir = dir, NewDir = newDir });
                        Directory.Move(dir, newDir);
                    }
                }

                FileInfoUtil.CreateFromDirectory(reportDir, zipFile);

                //把文件夹移动回去
                foreach (var item in moveList)
                {
                    Directory.Move(item.NewDir, item.OldDir);
                }
            }
            catch (Exception ex)
            {
                Logger.Error($"{ex.Message + ex.StackTrace}", ex);
                throw new OperationException(ex.Message);
            }
        }

        /// <summary>
        /// 作者：黄钧航
        /// 分享报告文件地址
        /// </summary>
        /// <param name="dto">任务对象</param>
        /// <returns></returns>
        public async Task<string> SharingReport(MsTaskDto dto) => dto.ShareReportType switch
        {
            ShareReportTypeEnum.Report
               => $"{webUrl}#/supplement/taskReportList/{dto.TaskId}",
            ShareReportTypeEnum.HotMap => string.IsNullOrEmpty(dto.HouseType) ?
               $"{webUrl}#/supplement/taskReportThreeDimensional/{dto.TaskId}" : $"{webUrl}#/supplement/taskReportThreeDimensional/{dto.TaskId}?HouseType= {dto.HouseType}",
            ShareReportTypeEnum.Modeling =>
                $"{webUrl}#/supplement/modelTaskPreview/{dto.TaskId}",
            ShareReportTypeEnum.ExternalWall =>
               $"{webUrl}#/supplement/externalWallTaskPreview/{dto.TaskId}",
            _ => throw new OperationException("此报告暂不支持分享")
        };

        /// <summary>
        /// 获取楼栋楼层的报告
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        /// <exception cref="Exception"></exception>
        public async Task<string> GetSummaryReportPath(GetSummaryReportRqDto request)
        {
            if (request == null || (int)request.ProjectType < 1) throw new OperationException("测量类型必须传");
            var data = CSMSTaskRepository.GetSummaryReport(request);
            if (data == null || data.ResultDataFilePath.IsNullOrWhiteSpace()) return string.Empty;
            data.ResultDataFilePath = data.ResultDataFilePath.Replace(@"\", @"/");
            int pIndex = data.ResultDataFilePath.IndexOf("task-report-data");
            if (pIndex == -1)
            {
                throw new OperationException(Localizer["YB0188"].Value);
            }
            string summaryReportPdfUrl = Path.Combine(data.ResultDataFilePath, data.TaskName, "测量报告", "测量报告.pdf").Replace(@"\", @"/");
            // 文件不存在按照新命名规范找
            if (!File.Exists(summaryReportPdfUrl))
            {
                string path = Path.Combine(data.ResultDataFilePath, data.TaskName, "测量报告");
                if (Directory.Exists(path))
                {
                    var files = Directory.GetFiles(path, $"*{request.ProjectType}_汇总报告.pdf");
                    if (files != null && files.Length > 0)
                    {
                        summaryReportPdfUrl = files[0];
                    }
                    else
                    {
                        throw new OperationException(Localizer["StatisServiceReportNotExists"].Value);
                    }
                }
                else
                {
                    Logger.Error($"GetReportList：汇总报告不存在{path}");
                    throw new OperationException(Localizer["StatisServiceReportNotExists"].Value);
                }
            }
            if (pIndex >= 0)
            {
                summaryReportPdfUrl = StatisService.ToTaskReportUrl(summaryReportPdfUrl.Substring(pIndex));
            }
            return summaryReportPdfUrl;
        }

        /// <summary>
        /// 获取任务的gltf文件列表
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async ValueTask<ApiResult> GetGltfListAsync(TaskIdWithHouseTypeDto dto)
        {
            var baseDir = await CSMSTaskRepository.GetResultDataFilePathAsync(dto.TaskId);
            if (!Directory.Exists(baseDir))
                return new ApiResult(AjaxCode.Fail, "该任务不存在建模结果数据");

            List<ModelingGltfDto> gltfList = new List<ModelingGltfDto>();
            var indexList = await MsTaskPointsRepository.GetAll().Where(x => x.TaskId == dto.TaskId && !x.IsDeleted && x.status == TaskPoints.PointStatus.测量完成).WhereIf(!string.IsNullOrEmpty(dto.HouseType), x => x.HouseTypeName == dto.HouseType).Select(x => x.pintIndex).OrderBy(x => x).ToListAsync();

            foreach (var item in indexList)
            {
                var targetDir = Path.Combine(baseDir, item.ToString(), "ifc_output");
                if (!Directory.Exists(targetDir))
                    continue;

                var gltfFile = Directory.GetFiles(targetDir, "*.gltf").FirstOrDefault();
                if (File.Exists(gltfFile))
                {
                    gltfList.Add(new ModelingGltfDto
                    {
                        Index = item,
                        GltfFile = ToModelingWebUrl(gltfFile)
                    });
                }
            }

            return ApiResult.Success().SetData(gltfList);
        }

        /// <summary>
        /// 将文件转化可访问的Url
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static string ToModelingWebUrl(string filePath)
        {
            var arr = filePath.Split("task-modeling-result");
            var path = arr.Length == 2 ? arr[1] : arr[0];
            var line = path.StartsWith("/") ? "" : "/";
            return $"{fileServer}/taskmodelingdata{line}{path}";
        }

        /// <summary>
        /// 下载外立面数据报告
        /// </summary>
        /// <param name="listTaskId"></param>
        /// <param name="folderName"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<List<string>> DownloadExternalReport(List<Guid> listTaskId, string folderName = "download")
        {
            if (listTaskId == null || listTaskId.Count == 0)
            {
                throw new OperationException(Localizer["YB0189"].Value);
            }
            else if (listTaskId.Count > 30)
            {
                //每次最多只能下载{0}个报告
                throw new OperationException(string.Format(Localizer["LimitDownloadReport"].Value, 30));
            }

            var urls = new List<string>();

            string dirPath = $"{taskReportData}/{folderName}/";
            var reportList = await CSMSTaskRepository.GetDownloadReportsAsync(listTaskId, dirPath);
            if (reportList.IsEmpty())
                throw new OperationException(Localizer["YB0192"].Value);

            //多线程下载
            List<Task> taskList = new List<Task>();
            foreach (var report in reportList)
            {
                Task task = new Task(() =>
                {
                    var url = CompressExternalwallReport(report);
                    if (!string.IsNullOrEmpty(url))
                        urls.Add(url);
                });
                task.Start();
                taskList.Add(task);
            }
            await Task.WhenAll(taskList);

            return urls;
        }

        /// <summary>
        /// 压缩外立面的数据报告文件
        /// </summary>
        /// <param name="report"></param>
        /// <returns></returns>
        private string CompressExternalwallReport(FileDownloadDto report)
        {
            try
            {
                // 如压缩文件已存在直接返回
                if (File.Exists(report.ZipFilePath))
                {
                    return StatisService.ToTaskReportUrl(report.ZipFilePath);
                }

                // 检查ReportOldDir目录是否存在  
                if (Directory.Exists(report.ReportOldDir))
                {
                    // 确保打包文件目录已删除，再打包
                    if (Directory.Exists(report.ReportDownloadDir))
                        Directory.Delete(report.ReportDownloadDir, true);

                    Directory.CreateDirectory(report.ReportDownloadDir);

                    // 获取ReportOldDir下的所有子目录  
                    var directories = Directory.GetDirectories(report.ReportOldDir);

                    string searchPattern = "*测量报告*.pdf";
                    string regexPattern = @"^\d+$";
                    // 遍历所有子目录  
                    foreach (var directory in directories)
                    {
                        // 检查子目录名称是否符合数字格式  
                        string dirName = new DirectoryInfo(directory).Name;
                        if (Regex.IsMatch(dirName, regexPattern))
                        {
                            // 获取所有包含测量报告的pdf文件  
                            var pdfFiles = Directory.GetFiles(directory, searchPattern);

                            // 复制找到的pdf文件到ReportDownloadDir目录  
                            foreach (var pdfFile in pdfFiles)
                            {
                                string destFilePath = Path.Combine(report.ReportDownloadDir, Path.GetFileName(pdfFile));
                                File.Copy(pdfFile, destFilePath, true);
                            }
                        }
                    }

                    FileInfoUtil.CreateFromDirectory(report.ReportDownloadDir, report.ZipFilePath);

                    //删除已经不需要的文件夹
                    if (Directory.Exists(report.ReportDownloadDir))
                        Directory.Delete(report.ReportDownloadDir, true);

                    if (File.Exists(report.ZipFilePath))
                        return StatisService.ToTaskReportUrl(report.ZipFilePath);
                }
            }
            catch (Exception ex)
            {
                logger.LogError($"打包压缩外立面数据报告失败：TaskId = {report.TaskId}，ErrMessage = {ex.Message}，{ex.StackTrace}");
            }

            return null;
        }

        /// <summary>
        /// 删除任务的数据报告压缩包
        /// </summary>
        /// <param name="taskId"></param>
        /// <param name="folderName"></param>
        public void DeleteCompressReport(Guid taskId, string folderName = "download")
        {
            string dirPath = $"{taskReportData}/{folderName}";

            var zipFileList = Directory.GetFiles(dirPath, $"*{taskId}.zip");
            if (zipFileList.IsEmpty())
                return;

            foreach (var zipFile in zipFileList) 
            {
                File.Delete(zipFile);
            }
        }
    }
}